package com.yunkeji.config.keymonitor.config;

import cn.hutool.core.collection.ListUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.yunkeji.common.constant.CacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;

// TODO 后面建议全部改为分布式消息队列处理,这是一种小项目暂时解决问题的一种方案
/**
 * key过期监听处理器
 *
 * @author 老张
 */
@Slf4j
@Component
public class RedisListenerHandel implements MessageListener {

    @Autowired private LockTemplate lockTemplate;

    private static List<String> SUFFIXS =
            ListUtil.list(
                    true,
                    // 这个是用户登录成功后,redis放置的一个key,监听到这个key后会执行置换Token逻辑
                    //   CacheConstants.TOKEN_CHANGE_PREFIX,
                    // 统一监听过期key的格式
                    CacheConstants.TOKEN_EXPIRE);

    @Override
    public void onMessage(Message message, byte[] pattern) {
        // TODO 添加分布式锁,避免多机器监听,添加后仍需要通过状态判断此处执行是否合理
        String msg = message.toString();
        log.info("key expire:{}", message);
        final LockInfo lockInfo =
                lockTemplate.lock(
                        CacheConstants.LOCK_REIDS_KEY_MONITOR + msg,
                        30000L,
                        5000L,
                        RedissonLockExecutor.class);
        if (null == lockInfo) {
            throw new RuntimeException("业务处理中,请稍后再试");
        }
        // 获取锁成功，处理业务
        try {
            String SUFFIX;
            Optional<String> first =
                    SUFFIXS.stream().filter(item -> msg.contains(item)).findFirst();
            if (first.isPresent()) {
                SUFFIX = first.get();
            } else {
                return;
            }
            // 用户做自己的业务处理即可,注意message.toString()可以获取失效的key
            String expiredKey = message.toString();
            String key = expiredKey.split(SUFFIX)[0] + SUFFIX;
            RedisListenerStrategy redisListenerStrategy = RedisListenerFactory.get(key);
            if (redisListenerStrategy != null) {
                redisListenerStrategy.execute(expiredKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lockTemplate.releaseLock(lockInfo);
        }
    }
}
